﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Configuration.Provider;
using System.Web.Configuration;
using Altairis.Sewen.Configuration;
using Altairis.Sewen.PageStore;

namespace Altairis.Sewen {
    public static class PageStoreManager {

        // Provider infrastructure

        /// <summary>
        /// Initializes the <see cref="PageStoreManager"/> class.
        /// </summary>
        static PageStoreManager() {

            // Get configuration info
            var config = ConfigurationManager.GetSection("altairis.sewen") as SewenConfigurationSection;
            if (config == null || config.Store.Providers == null || config.Store.Providers.Count == 0) throw new ProviderException("No page store providers specified");

            // Instantiate the providers
            Providers = new PageStoreProviderCollection();
            ProvidersHelper.InstantiateProviders(config.Store.Providers, Providers, typeof(PageStoreProvider));
            Providers.SetReadOnly();

            // Get default provider
            DefaultProvider = Providers[config.Store.DefaultProvider];
        }

        /// <summary>
        /// Gets the default provider.
        /// </summary>
        public static PageStoreProvider DefaultProvider { get; private set; }

        /// <summary>
        /// Gets the collection of providers.
        /// </summary>
        public static PageStoreProviderCollection Providers { get; private set; }

        // Access methods

        /// <summary>
        /// Loads latest available version of the page.
        /// </summary>
        /// <param name="name">Page title or slug.</param>
        /// <returns>Returns instance of <c>SewenPage</c> class or <c>null</c> when such page is not found.</returns>
        public static SewenPage LoadPage(string name) {
            return DefaultProvider.LoadPage(name);
        }

        /// <summary>
        /// Loads the version of the page, which was latest available in time specified by <paramref name="version" /> parameter.
        /// </summary>
        /// <param name="name">Page title or slug.</param>
        /// <param name="version">The time decisive for version.</param>
        /// <returns>
        /// Returns instance of <c>SewenPage</c> class or <c>null</c> when such page is not found.
        /// </returns>
        public static SewenPage LoadPage(string name, DateTime version) {
            return DefaultProvider.LoadPage(name, version);
        }

        /// <summary>
        /// Loads the version of the page, which was latest available in time specified by <paramref name="versionString" /> parameter.
        /// </summary>
        /// <param name="name">Page title or slug.</param>
        /// <param name="versionString">The time decisive for version as string in <c>yyyyMMddHHmmssfff</c> format.</param>
        /// <returns>
        /// Returns instance of <c>SewenPage</c> class or <c>null</c> when such page is not found.
        /// </returns>
        /// <remarks>
        /// This overload is intended for use by data binding scenarios, where date in strongly-typed format 
        /// may be mot always available. Wher the <paramref name="versionString" /> format cannot be parsed 
        /// as valid <c>DateTime</c>, newest version is returned.
        /// </remarks>
        public static SewenPage LoadPage(string name, string versionString) {
            DateTime version;
            if (!DateTime.TryParseExact(versionString, "yyyyMMddHHmmssfff", null, System.Globalization.DateTimeStyles.AssumeLocal, out version)) version = DateTime.Now;
            return DefaultProvider.LoadPage(name, version);
        }

        /// <summary>
        /// Deletes all versions of the page.
        /// </summary>
        /// <param name="name">Page title or slug.</param>
        /// <returns>Returns <c>true</c> when page was deleted, <c>false</c> otherwise.</returns>
        public static bool DeletePage(string name) {
            return DefaultProvider.DeletePage(name);
        }

        /// <summary>
        /// Deletes all versions of the page.
        /// </summary>
        /// <param name="name">Page title or slug.</param>
        /// <param name="version">The version time. This must be the exact page version time.</param>
        /// <returns>Returns <c>true</c> when page was deleted, <c>false</c> otherwise.</returns>
        public static bool DeletePage(string name, DateTime version) {
            return DefaultProvider.DeletePage(name, version);
        }

        /// <summary>
        /// Saves new version of the page or creates new page if no previous version is found.
        /// </summary>
        /// <param name="page">The page to be saved.</param>
        public static void SavePage(SewenPage page) {
            DefaultProvider.SavePage(page);
        }

        /// <summary>
        /// Loads all existing page versions.
        /// </summary>
        /// <param name="name">Page title or slug.</param>
        /// <returns>Returns all available versions of page or empty <code>IEnumerable&lt;&gt;</code> when no such page exists.</returns>
        public static IEnumerable<SewenPage> LoadPageVersions(string name) {
            return DefaultProvider.LoadPageVersions(name);
        }

        /// <summary>
        /// Finds all pages whose title contains the specified string.
        /// </summary>
        /// <param name="searchString">The search string.</param>
        /// <returns>List of all pages whose titles contain the specified string, or empty <code>IEnumerable&lt;&gt;</code> when no such pages found.</returns>
        public static IEnumerable<SewenPage> FindPagesByTitle(string searchString) {
            return DefaultProvider.FindPagesByTitle(searchString);
        }

        /// <summary>
        /// Finds all pages whose title begins, ends with or contains the specified string.
        /// </summary>
        /// <param name="searchString">The search string.</param>
        /// <param name="mode">The search mode.</param>
        /// <returns>List of all pages whose titles contain the specified string, or empty <code>IEnumerable&lt;&gt;</code> when no such pages found.</returns>
        public static IEnumerable<SewenPage> FindPagesByTitle(string searchString, StringSearchMode mode) {
            return DefaultProvider.FindPagesByTitle(searchString, mode);
        }

    }
}
